#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include "omp.h"
#include "mkl.h"
#include <malloc.h>
#include <assert.h>

#define DELTA (0.001)

void Init(double *A, int w, int h)
{
    for(int j=0; j<w; j++)
        for(int i=0; i<h; i++)        
            A[j*h+i]=rand();
}

bool CompareMatrix(double *gC, double *C, int size, double delta)
{
    for(int i=0; i<size; i++)
        if(fabs(gC[i]-C[i])>delta)
            return false;

    return true;
}

void MatrixMultiplication(double* A, double* B, double *C, int aH, int aW, int bW);

void MyMatrixMultiplication(double* A, double* B, double *C,  int aH, int aW, int bW)
{
	cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, aH, bW, aW, 1.0, A, aH, B, aW, 0.0, C, aH);
}

int main(int argc, char* argv[])
{
    double *A, *B, *C, *gC;
    int seed = 666;
    bool rez;
    int m = 0, n = 0, k = 0;
    double s, f;

    if(argc < 5)
    {
        printf("Error!!!\nUsage:\n");
        printf("  <appName> <M> <N> <K> <seed>\n");    
        return 0;
    }

    m = atoi(argv[1]);
    n = atoi(argv[2]);  
    k = atoi(argv[3]);  
    seed = atoi(argv[4]);  

    srand(seed);

    A=new double[m*n];
    B=new double[n*k];
    C=new double[m*k];
    gC=new double[m*k]; 

    Init(A, n, m);
    Init(B, k, n);

    s = omp_get_wtime();
#pragma noinline
    MatrixMultiplication(A, B, C, m, n, k);
    f = omp_get_wtime();

    printf("Execution time: %lf\n", f-s);
	//for (int i=0; i<m; i++)
	//{
	//	printf("\n");
	//	for (int j=0; j<k; j++)
	//	{
	//		printf("%d ", C[i + j*m]);
	//	}
	//}

    s = omp_get_wtime();
    MyMatrixMultiplication(A, B, gC, m, n, k);
    f = omp_get_wtime();
    printf("My execution time: %lf\n", f-s);

    rez=CompareMatrix(gC, C, m*k, DELTA);
    printf("Compare: %i\n",rez);

    delete[] A;
    delete[] B;
    delete[] C;
    delete[] gC;
    return 0;
} 